function VM(options = {}) {
  this.$options = options 
  var data = this._data = this.$options.data
  observe(data)
  for (let k in data) {
    Object.defineProperty(this, k, {
      enumerable: true,
      get() {
        return this._data[k]
        
      },
      set(newVal) {
        this._data[k] = newVal
        
      }
    })
  }
  new Compile(options.el,this)
}

function Compile(el,vmm) {
  
vmm.$el = document.querySelector(el)
var fragment = document.createDocumentFragment()
  while (child = vmm.$el.firstChild) {
   
    fragment.appendChild(child)
  }
  replace(fragment)
  function replace(fragment) {
    Array.from(fragment.childNodes).forEach(function (node) {
      let text = node.textContent
      let reg = /\{\{(.*)\}\}/;
      if (node.nodeType === 3 && reg.test(text)) {
        // console.log(RegExp.$1);
        let arr = RegExp.$1.split('.') // [a,a] [b]
        // console.log(arr);
        let val = vmm
        arr.forEach(function (k) {  // (a)
          val = val[k]
        })
        new Watch(vmm, RegExp.$1, function (newVal) {
          node.textContent = text.replace(/\{\{(.*)\}\}/,newVal)
        })
        node.textContent = text.replace(/\{\{(.*)\}\}/,val)

      }
      if (node.nodeType === 1) {
        // 元素节点
        let nodeAttrs = node.attributes;
        Array.from(nodeAttrs).forEach(function (attr) {
          console.log(attr);
          let name = attr.name  // 
          let exp = attr.value
          // console.log(name,exp);
          if (name.indexOf('v-') == 0) {
            node.value = vmm[exp]
          }
          new Watch(vmm, exp, function (newVal) {
            node.value = newVal
          })
          node.addEventListener("input", function (e) {
            let newVal = e.target.value
            vmm[exp] = newVal
          })
        })
      }
      if (node.childNodes) {
        replace(node)
      }
      
    })

  }

  vmm.$el.appendChild(fragment)

}






function Observe(data) {
  let dep = new Dep()
  
  for (var k in data) {
    var val = data[k]
    observe(val)
    Object.defineProperty(data, k, {
      enumerable: true,
      get() {
        Dep.target && dep.addSub(Dep.target)
        return val
        
      }, set(newVal) {
        if (newVal === val) {
          return;
        }
        val = newVal
        observe(newVal)
        dep.notify()
      }
     })
}

}




function observe(data) {
  if (typeof data !== 'object') return;
  return  new Observe(data)
}

/// 发布订阅

function Dep() {
  this.subs = []
}

Dep.prototype.addSub = function (sub) {
  this.subs.push(sub)
}

Dep.prototype.notify = function () {
  this.subs.forEach(sub => sub.update())
}


function Watch(vmm, exp, fn) {
  this.fn = fn
  this.vmm = vmm
  this.exp = exp 
  Dep.target = this
  let val = vmm
  let arr = exp.split('.')
  arr.forEach(function (k) {
    val = val [k]
  })
  Dep.target = null
}

Watch.prototype.update = function () {
  let val = this.vmm
  let arr = this.exp.split('.')
  arr.forEach(function (k){
    val = val[k]
  })
  this.fn(val)
}

